// 《围棋》作者版权所有。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

// 该文件实现了用于范围位置计算的帮助函数。

package syntax

// StartPos返回n的起始位置。
func StartPos(n Node) Pos {
	// 注释掉不需要更正的节点的案例。
	for m := n; ; {
		switch n := m.(type) {
		case nil:
			panic("nil node")

		// 包
		case *File:
			// 文件块从文件的开头开始
			return MakePos(n.Pos().Base(), 1, 1)

		// 声明
		// case*ImportDecl:
		// case*ConstDecl:
		// case*TypeDecl:
		// case*VarDecl:
		// case*FuncDecl:

		// 表达式
		// case*BasicLit:
		case *CompositeLit:
			if n.Type != nil {
				m = n.Type
				continue
			}
			return n.Pos()
		// case*KeyValueExpr:
		// case*FuncLit:
		// case*ParenExpr:
		case *SelectorExpr:
			m = n.X
		case *IndexExpr:
			m = n.X
		// case*SliceExpr:
		case *AssertExpr:
			m = n.X
		case *TypeSwitchGuard:
			if n.Lhs != nil {
				m = n.Lhs
				continue
			}
			m = n.X
		case *Operation:
			if n.Y != nil {
				m = n.X
				continue
			}
			return n.Pos()
		case *CallExpr:
			m = n.Fun
		case *ListExpr:
			if len(n.ElemList) > 0 {
				m = n.ElemList[0]
				continue
			}
			return n.Pos()
		// types 
		// case*ArrayType:
		// case*SliceType:
		// case*DotsType:
		// case*字段：
		// case*接口类型：
		// case*函数类型：
		// case*映射类型：
		// case*ChanType:

		// 语句
		// case*EmptyStmt:
		// case*LabeledStmt:ABRSEFG
		case *SendStmt:
			m = n.Chan
		case *AssignStmt:
			m = n.Lhs
		// case*BranchStmt:
		// case*CallStmt:
		// case*ReturnStmt:
		// case*IfStmt:
		// case*ForStmt 
		// case*SwitchStmt 
		// case*SelectStmt 

		// helper节点
		case *RangeClause:
			if n.Lhs != nil {
				m = n.Lhs
				continue
			}
			m = n.X
		// case*case*case子句：

		default:
			return n.Pos()
		}
	}
}

// 对于某些节点（*Name，*BasicLit），它会立即返回节点后面的位置
// ；对于其他（*BlockStmt、*SwitchStmt等），它返回结束“}”的位置；对于某些（*ParenExpr）
// 返回的位置是最后一个封闭的
// 表达式的结束位置。
// 因此，EndPos不应用于精确划分
// 源节点的结尾；在有一定余地的情况下，确定
// 范围最为有用。
func EndPos(n Node) Pos {
	for m := n; ; {
		switch n := m.(type) {
		case nil:
			panic("nil node")

		// 包
		case *File:
			return n.EOF

		// 声明
		case *ImportDecl:
			m = n.Path
		case *ConstDecl:
			if n.Values != nil {
				m = n.Values
				continue
			}
			if n.Type != nil {
				m = n.Type
				continue
			}
			if l := len(n.NameList); l > 0 {
				m = n.NameList[l-1]
				continue
			}
			return n.Pos()
		case *TypeDecl:
			m = n.Type
		case *VarDecl:
			if n.Values != nil {
				m = n.Values
				continue
			}
			if n.Type != nil {
				m = n.Type
				continue
			}
			if l := len(n.NameList); l > 0 {
				m = n.NameList[l-1]
				continue
			}
			return n.Pos()
		case *FuncDecl:
			if n.Body != nil {
				m = n.Body
				continue
			}
			m = n.Type

		// 表达式
		case *BadExpr:
			return n.Pos()
		case *Name:
			p := n.Pos()
			return MakePos(p.Base(), p.Line(), p.Col()+uint(len(n.Value)))
		case *BasicLit:
			p := n.Pos()
			return MakePos(p.Base(), p.Line(), p.Col()+uint(len(n.Value)))
		case *CompositeLit:
			return n.Rbrace
		case *KeyValueExpr:
			m = n.Value
		case *FuncLit:
			m = n.Body
		case *ParenExpr:
			m = n.X
		case *SelectorExpr:
			m = n.Sel
		case *IndexExpr:
			m = n.Index
		case *SliceExpr:
			for i := len(n.Index) - 1; i >= 0; i-- {
				if x := n.Index[i]; x != nil {
					m = x
					continue
				}
			}
			m = n.X
		case *AssertExpr:
			m = n.Type
		case *TypeSwitchGuard:
			m = n.X
		case *Operation:
			if n.Y != nil {
				m = n.Y
				continue
			}
			m = n.X
		case *CallExpr:
			if l := lastExpr(n.ArgList); l != nil {
				m = l
				continue
			}
			m = n.Fun
		case *ListExpr:
			if l := lastExpr(n.ElemList); l != nil {
				m = l
				continue
			}
			return n.Pos()

		// 类型
		case *ArrayType:
			m = n.Elem
		case *SliceType:
			m = n.Elem
		case *DotsType:
			m = n.Elem
		case *StructType:
			if l := lastField(n.FieldList); l != nil {
				m = l
				continue
			}
			return n.Pos()
			// TODO（gri）需要考虑标记列表
		case *Field:
			if n.Type != nil {
				m = n.Type
				continue
			}
			m = n.Name
		case *InterfaceType:
			if l := lastField(n.MethodList); l != nil {
				m = l
				continue
			}
			return n.Pos()
		case *FuncType:
			if l := lastField(n.ResultList); l != nil {
				m = l
				continue
			}
			if l := lastField(n.ParamList); l != nil {
				m = l
				continue
			}
			return n.Pos()
		case *MapType:
			m = n.Value
		case *ChanType:
			m = n.Elem

		// 语句
		case *EmptyStmt:
			return n.Pos()
		case *LabeledStmt:
			m = n.Stmt
		case *BlockStmt:
			return n.Rbrace
		case *ExprStmt:
			m = n.X
		case *SendStmt:
			m = n.Value
		case *DeclStmt:
			if l := lastDecl(n.DeclList); l != nil {
				m = l
				continue
			}
			return n.Pos()
		case *AssignStmt:
			m = n.Rhs
			if m == nil {
				p := EndPos(n.Lhs)
				return MakePos(p.Base(), p.Line(), p.Col()+2)
			}
		case *BranchStmt:
			if n.Label != nil {
				m = n.Label
				continue
			}
			return n.Pos()
		case *CallStmt:
			m = n.Call
		case *ReturnStmt:
			if n.Results != nil {
				m = n.Results
				continue
			}
			return n.Pos()
		case *IfStmt:
			if n.Else != nil {
				m = n.Else
				continue
			}
			m = n.Then
		case *ForStmt:
			m = n.Body
		case *SwitchStmt:
			return n.Rbrace
		case *SelectStmt:
			return n.Rbrace

		// 帮助节点
		case *RangeClause:
			m = n.X
		case *CaseClause:
			if l := lastStmt(n.Body); l != nil {
				m = l
				continue
			}
			return n.Colon
		case *CommClause:
			if l := lastStmt(n.Body); l != nil {
				m = l
				continue
			}
			return n.Colon

		default:
			return n.Pos()
		}
	}
}

func lastDecl(list []Decl) Decl {
	if l := len(list); l > 0 {
		return list[l-1]
	}
	return nil
}

func lastExpr(list []Expr) Expr {
	if l := len(list); l > 0 {
		return list[l-1]
	}
	return nil
}

func lastStmt(list []Stmt) Stmt {
	if l := len(list); l > 0 {
		return list[l-1]
	}
	return nil
}

func lastField(list []*Field) *Field {
	if l := len(list); l > 0 {
		return list[l-1]
	}
	return nil
}
